package com.ht.modules.authentication.utils;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.google.common.base.Joiner;
import com.ht.constant.DataBaseConstant;
import com.ht.entity.SysUserCacheInfo;
import com.ht.exception.JeecgBootException;
import com.ht.utils.JeecgDataAutorUtils;
import com.ht.utils.SpringContextUtils;
import com.ht.utils.oConvertUtils;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpSession;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.Date;

@Slf4j
@Component
public class JwtUtil {

    // PC的TOKEN过期时间三小时
    public static final long EXPIRE_TIME_PC = 3 * 60 * 60 * 1000;
    // APP的TOKEN过期时间七天
    public static final long EXPIRE_TIME_APP = 7 * 24 * 60 * 60 * 1000;

    public static void main(String[] args) {
        JwtUtil jwtUtil = new JwtUtil();
        String token = jwtUtil.generateToken("dt_1", "admin", "asdhnkj", 1000 * 60 * 5);
        System.out.println("token = " + token);
        String info = jwtUtil.getInfo("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE3NTEyNjY5MDcsImR0XzEiOiJhZG1pbiJ9.OUtuF4O-0Nj-fKT5W0BfZSDyV4APfcnzmKElMBrwMaM", "dt_1");
        System.out.println("info = " + info);
    }

    /**
     * 生成token
     *
     * @param key         键
     * @param value       值
     * @param tokenSecret 密钥
     * @param expireTime  过期时间
     * @return token
     */
    public String generateToken(String key, String value, String tokenSecret, long expireTime) {
        try {
            Algorithm algorithm = Algorithm.HMAC256(tokenSecret);
            // 附带username信息
            return JWT.create().withClaim(key, value).withExpiresAt(new Date(System.currentTimeMillis() + expireTime)).sign(algorithm);
        } catch (Exception e) {
            throw new JeecgBootException("token生成失败", e);
        }
    }

    /**
     * 校验token是否正确
     *
     * @param token  token
     *               key 键
     *               value 值
     * @param secret 密钥
     * @return 是否正确
     */
    public boolean verify(String token, String key, String value, String secret) {
        try {
            Algorithm algorithm = Algorithm.HMAC256(secret);
            JWTVerifier verifier = JWT.require(algorithm).withClaim(key, value).build();
            verifier.verify(token);
            return true;
        } catch (Exception e) {
            log.error("token验证失败", e);
            return false;
        }
    }


    /**
     * 获得token中的信息无需secret解密也能获得
     */
    public String getInfo(String token, String key) {
        try {
            DecodedJWT jwt = JWT.decode(token);
            return jwt.getClaim(key).asString();
        } catch (JWTDecodeException e) {
            return null;
        }
    }


    /**
     * 校验token是否正确
     *
     * @param token  密钥
     * @param secret 用户的密码
     * @return 是否正确
     */
    public boolean verify(String token, String username, String secret) {
        try {
            JWTVerifier verifier = JWT.require(Algorithm.HMAC256(secret)).withClaim("username", username).build();
            verifier.verify(token);
            return true;
        } catch (Exception exception) {
            return false;
        }
    }

    /**
     * 获得token中的信息无需secret解密也能获得
     *
     * @return token中包含的用户名
     */
    public static String getUsername(String token) {
        try {
            DecodedJWT jwt = JWT.decode(token);
            return jwt.getClaim("username").asString();
        } catch (JWTDecodeException e) {
            return null;
        }
    }

    /**
     * 获取过期时间
     */
    public static Date getExpiresDate(String token) {
        try {
            DecodedJWT jwt = JWT.decode(token);
            return jwt.getExpiresAt();
        } catch (JWTDecodeException e) {
            return null;
        }
    }

    /**
     * 根据固定时间生成token
     */
    public static String signByFixedTime(String username, String secret, Date date) {
        Algorithm algorithm = Algorithm.HMAC256(secret);
        // 附带username信息
        return JWT.create().withClaim("username", username).withExpiresAt(date).sign(algorithm);

    }

    /**
     * 生成签名,5min后过期
     *
     * @param username 用户名
     * @param secret   用户的密码
     * @return 加密的token
     */
    public static String signPC(String username, String secret) {
        Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME_PC);
        Algorithm algorithm = Algorithm.HMAC256(secret);
        // 附带username信息
        return JWT.create().withClaim("username", username).withExpiresAt(date).sign(algorithm);

    }

    /**
     * 生成签名,5min后过期
     *
     * @param username 用户名
     * @param secret   用户的密码
     * @return 加密的token
     */
    public static String signAPP(String username, String secret) {
        Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME_APP);
        Algorithm algorithm = Algorithm.HMAC256(secret);
        // 附带username信息
        return JWT.create().withClaim("username", username).withExpiresAt(date).sign(algorithm);

    }

    /**
     * 根据request中的token获取用户账号
     */
    public static String getUserNameByToken(HttpServletRequest request) throws JeecgBootException {
        String accessToken = request.getHeader("X-Access-Token");
        String username = getUsername(accessToken);
        if (oConvertUtils.isEmpty(username)) {
            throw new JeecgBootException("未获取到用户");
        }
        return username;
    }

    /**
     * 从session中获取变量
     */
    public static String getSessionData(String key) {
        //${myVar}%
        //得到${} 后面的值
        String moshi = "";
        if (key.contains("}")) {
            moshi = key.substring(key.indexOf("}") + 1);
        }
        String returnValue = null;
        if (key.contains("#{")) {
            key = key.substring(2, key.indexOf("}"));
        }
        if (oConvertUtils.isNotEmpty(key)) {
            HttpSession session = SpringContextUtils.getHttpServletRequest().getSession();
            returnValue = (String) session.getAttribute(key);
        }
        //结果加上${} 后面的值
        if (returnValue != null) {
            returnValue = returnValue + moshi;
        }
        return returnValue;
    }

    /**
     * 从当前用户中获取变量
     */
    public static String getUserSystemData(String key, SysUserCacheInfo user) {
        if (user == null) {
            user = JeecgDataAutorUtils.loadUserInfo();
        }
        //#{sys_user_code}%
        String moshi = "";
        if (key.contains("}")) {
            moshi = key.substring(key.indexOf("}") + 1);
        }
        String returnValue = null;
        //针对特殊标示处理#{sysOrgCode}，判断替换
        if (key.contains("#{")) {
            key = key.substring(2, key.indexOf("}"));
        } else {
            key = key;
        }
        //替换为系统登录用户帐号
        if (key.equals(DataBaseConstant.SYS_USER_CODE) || key.equals(DataBaseConstant.SYS_USER_CODE_TABLE)) {
            returnValue = user.getSysUserCode();
        }
        //替换为系统登录用户真实名字
        if (key.equals(DataBaseConstant.SYS_USER_NAME) || key.equals(DataBaseConstant.SYS_USER_NAME_TABLE)) {
            returnValue = user.getSysUserName();
        }
        //替换为系统用户登录所使用的机构编码
        if (key.equals(DataBaseConstant.SYS_ORG_CODE) || key.equals(DataBaseConstant.SYS_ORG_CODE_TABLE)) {
            returnValue = user.getSysOrgCode();
        }
        //替换为系统用户所拥有的所有机构编码
        if (key.equals(DataBaseConstant.SYS_MULTI_ORG_CODE)) {
            if (user.isOneDepart()) {
                returnValue = user.getSysMultiOrgCode().get(0);
            } else {
                returnValue = Joiner.on(",").join(user.getSysMultiOrgCode());
            }
        }
        //替换为当前系统时间(年月日)
        if (key.equals(DataBaseConstant.SYS_DATE) || key.equals(DataBaseConstant.SYS_DATE_TABLE)) {
            returnValue = user.getSysDate();
        }
        //替换为当前系统时间（年月日时分秒）
        if (key.equals(DataBaseConstant.SYS_TIME) || key.equals(DataBaseConstant.SYS_TIME_TABLE)) {
            returnValue = user.getSysTime();
        }
        //流程状态默认值（默认未发起）
        if (key.equals(DataBaseConstant.BPM_STATUS_TABLE)) {
            returnValue = "1";
        }
        if (returnValue != null) {
            returnValue = returnValue + moshi;
        }
        return returnValue;
    }
}
